
/*********************************************************************************
* Copyright (c) zhujinyang.
* All rights reserved.
*
* \file
*
* adc driver
*
* 
*********************************************************************************/
#include "os_ext_api.h"
#include "stm32h7xx_ll_gpio.h"
#include "hal_gpio_drv.h"



/*
********************************************************************************
* define config parameters
********************************************************************************
*/



/*
********************************************************************************
* define struct
********************************************************************************
*/
typedef struct {
    GPIO_TypeDef *           gpio_base;
    INT32U                   gpio_pin;
    INT8U                    in_out;
    INT8S                    init_level;
} GPIO_CH_TBL_T;



/*
********************************************************************************
* define gpio table
********************************************************************************
*/
#ifdef GPIO_DEF
#undef GPIO_DEF
#endif

#define GPIO_DEF(IO_CH, GPIO_BASE, GPIO_PIN, IN_OUT, INIT_LEVEL)  \
        {GPIO_BASE, GPIO_PIN, IN_OUT, INIT_LEVEL},

static const GPIO_CH_TBL_T  s_gpio_ch_tbl[] = {
    #include "hal_gpio_def.table"
    {0, 0, 0, 0}
};


/**********************************************************************************
* \brief:       configure channel gpio
* \param[in]:   the pointer of channel
* \return:      none
**********************************************************************************/
static void config_gpio_ch(const GPIO_CH_TBL_T *ch_reg)
{
    LL_GPIO_InitTypeDef cfg;
    
    if (ch_reg->init_level < 0) {
        return;
    }
    
    cfg.Pin        = ch_reg->gpio_pin;
    cfg.Speed      = LL_GPIO_SPEED_FAST;
    cfg.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    cfg.Alternate  = LL_GPIO_AF_0;
    if (ch_reg->gpio_base != 0) {
        switch (ch_reg->in_out) {
        case GPIO_DIR_OUT:
            cfg.Mode       = LL_GPIO_MODE_OUTPUT;
            cfg.Pull       = LL_GPIO_PULL_NO;
            LL_GPIO_Init(ch_reg->gpio_base, &cfg);
            if (ch_reg->init_level) {
                LL_GPIO_SetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
            } else {
                LL_GPIO_ResetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
            }
            break;

        case GPIO_DIR_OUT_PULLUP:
            cfg.Mode       = LL_GPIO_MODE_OUTPUT;
            cfg.Pull       = LL_GPIO_PULL_UP;
            LL_GPIO_Init(ch_reg->gpio_base, &cfg);
            if (ch_reg->init_level) {
                LL_GPIO_SetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
            } else {
                LL_GPIO_ResetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
            }
            break;

        case GPIO_DIR_OUT_PULLDN:
            cfg.Mode       = LL_GPIO_MODE_OUTPUT;
            cfg.Pull       = LL_GPIO_PULL_DOWN;
            LL_GPIO_Init(ch_reg->gpio_base, &cfg);
            if (ch_reg->init_level) {
                LL_GPIO_SetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
            } else {
                LL_GPIO_ResetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
            }
            break;

        case GPIO_DIR_IN:
            cfg.Mode       = LL_GPIO_MODE_INPUT;
            cfg.Pull       = LL_GPIO_PULL_NO;
            LL_GPIO_Init(ch_reg->gpio_base, &cfg);
            break;

        case GPIO_DIR_IN_PULLUP:
            cfg.Mode       = LL_GPIO_MODE_INPUT;
            cfg.Pull       = LL_GPIO_PULL_UP;
            LL_GPIO_Init(ch_reg->gpio_base, &cfg);
            break;

        case GPIO_DIR_IN_PULLDN:
            cfg.Mode       = LL_GPIO_MODE_INPUT;
            cfg.Pull       = LL_GPIO_PULL_DOWN;
            LL_GPIO_Init(ch_reg->gpio_base, &cfg);
            break;
            
        default:
           break;
        }

    }
}


/**********************************************************************************
* \brief:       Reset PIN Orientation Status
* \param[in]:   ch: see hal_gpio_def.table
* \return:      -1 : channel abnormal, 0: success
**********************************************************************************/
INT32S hal_gpio_reset(INT32U ch)
{
    LL_GPIO_InitTypeDef  cfg;
    const GPIO_CH_TBL_T *ch_reg;

    if (ch >= GPIO_IO_CH_MAX) {
        return -1;
    }

    ch_reg = &s_gpio_ch_tbl[ch];
    
    cfg.Pin        = ch_reg->gpio_pin;
    cfg.Speed      = LL_GPIO_SPEED_FAST;
    cfg.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    cfg.Alternate  = LL_GPIO_AF_0;
    switch (ch_reg->in_out) {
    case GPIO_DIR_OUT:
        cfg.Mode       = LL_GPIO_MODE_OUTPUT;
        cfg.Pull       = LL_GPIO_PULL_NO;
        LL_GPIO_Init(ch_reg->gpio_base, &cfg);
        //LL_GPIO_SetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
        break;

    case GPIO_DIR_OUT_PULLUP:
        cfg.Mode       = LL_GPIO_MODE_OUTPUT;
        cfg.Pull       = LL_GPIO_PULL_UP;
        LL_GPIO_Init(ch_reg->gpio_base, &cfg);
        //LL_GPIO_SetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
        break;

    case GPIO_DIR_OUT_PULLDN:
        cfg.Mode       = LL_GPIO_MODE_OUTPUT;
        cfg.Pull       = LL_GPIO_PULL_DOWN;
        LL_GPIO_Init(ch_reg->gpio_base, &cfg);
        //LL_GPIO_SetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
        break;

    case GPIO_DIR_IN:
        cfg.Mode       = LL_GPIO_MODE_INPUT;
        cfg.Pull       = LL_GPIO_PULL_NO;
        LL_GPIO_Init(ch_reg->gpio_base, &cfg);
        break;

    case GPIO_DIR_IN_PULLUP:
        cfg.Mode       = LL_GPIO_MODE_INPUT;
        cfg.Pull       = LL_GPIO_PULL_UP;
        LL_GPIO_Init(ch_reg->gpio_base, &cfg);
        break;

    case GPIO_DIR_IN_PULLDN:
        cfg.Mode       = LL_GPIO_MODE_INPUT;
        cfg.Pull       = LL_GPIO_PULL_DOWN;
        LL_GPIO_Init(ch_reg->gpio_base, &cfg);
        break;
        
    default:
       break;
    }

    return 0;
}


/**********************************************************************************
* \brief:       set gpio output level value
* \param[in]:   ch: see hal_gpio_def.table
* \return:      -1 : channel abnormal, 0: success
**********************************************************************************/
INT32S hal_gpio_output_high(INT32U ch)
{
    const GPIO_CH_TBL_T *ch_reg;

    if (ch >= GPIO_IO_CH_MAX) {
        return -1;
    }

    ch_reg = &s_gpio_ch_tbl[ch];
    
    LL_GPIO_SetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
    
    return 0; 
}

/**********************************************************************************
* \brief:       reset gpio output level value
* \param[in]:   ch: see hal_gpio_def.table
* \return:      -1 : channel abnormal, 0: success
**********************************************************************************/
INT32S hal_gpio_output_low(INT32U ch)
{
    const GPIO_CH_TBL_T *ch_reg;

    if (ch >= GPIO_IO_CH_MAX) {
        return -1;
    }

    ch_reg = &s_gpio_ch_tbl[ch];
    
    LL_GPIO_ResetOutputPin(ch_reg->gpio_base, ch_reg->gpio_pin);
    
    return 0; 
}

/**********************************************************************************
* \brief:       toggle gpio output level value
* \param[in]:   ch: see hal_gpio_def.table
* \return:      -1 : channel abnormal, 0: success
**********************************************************************************/
INT32S hal_gpio_toggleoutput(INT32U ch)
{
    const GPIO_CH_TBL_T *ch_reg;

    if (ch >= GPIO_IO_CH_MAX) {
        return -1;
    }

    ch_reg = &s_gpio_ch_tbl[ch];
    
    LL_GPIO_TogglePin(ch_reg->gpio_base, ch_reg->gpio_pin);

    return 0;
}


/**********************************************************************************
* \brief:       read gpio input statue, high level or low level
* \param[in]:   ch: see hal_gpio_def.table
* \return:      -1 : channel abnormal, 0: low level, 1: high level
**********************************************************************************/
INT32S hal_gpio_readinput(INT32U ch)
{
    const GPIO_CH_TBL_T *ch_reg;

    if (ch >= GPIO_IO_CH_MAX) {
        return -1;
    }
    
    ch_reg = &s_gpio_ch_tbl[ch];
    
    return LL_GPIO_IsInputPinSet(ch_reg->gpio_base, ch_reg->gpio_pin);
}

/**********************************************************************************
* \brief:       gpio driver init
* \param[in]:   none
* \return:      none
**********************************************************************************/
void hal_gpio_initdrv(void)
{
    INT32U i;

    for (i = 0; i < sizeof(s_gpio_ch_tbl) / sizeof(s_gpio_ch_tbl[0]); i++) {
        config_gpio_ch(&s_gpio_ch_tbl[i]);
    }
}







